package com.translate.commons.asynctask;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Timer;
import java.util.TimerTask;

import com.translate.commons.utils.SpringContextHelper;
import org.springframework.beans.factory.annotation.Autowired;

/********************************************
 * 异步任务执行基类.<br>
 *********************************************/
public abstract class AsyncTaskBase implements Runnable {

    /* SPRING上下文操作对象 */
    private SpringContextHelper contextHelper;
    /* 执行时所需要的参数 */
    private Object[] argments;

    private String taskId;

    /* 线程池的引用，只有线程被放到线程池后，该变量才会有对象，不然就是个NULL */
    private AsyncTaskExecutor taskExecutor;
    /* 线程自动销毁时间 */
    private int destroyTime = 0;

    /********************************************
     * 获取构造时传入的参数集.<br>
     * 方法业务逻辑详细描述……<br>
     * 参数名 参数类型 参数描述
     * @return 返回类型 返回类型描述
     * <br>
     *********************************************/
    protected Object[] getArgments() {
        return argments;
    }

    /********************************************
     * 构造方法.<br>
     * 构造方法业务逻辑详细描述……<br>
     * 参数名 参数类型 参数描述
     * <br>
     *********************************************/
    public AsyncTaskBase(SpringContextHelper sch, Object... args) {
        contextHelper = sch;
        argments = args;
        init();
    }

    private void init() {
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field field : fields) {
            Annotation annotations = field.getAnnotation(Autowired.class);
            if (annotations != null) {
                field.setAccessible(true);
                try {
                    field.set(	this,
                            SpringContextHelper.getApplicationContext().getBean((Class) field.getGenericType()));
                    field.setAccessible(false);
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /********************************************
     * 执行方法.<br>
     * 所有的执行逻辑都集中在这个方法<br>
     * 参数名 参数类型 参数描述
     * @return 返回类型 返回类型描述
     * <br>
     *********************************************/
    public abstract void execute();

    /********************************************
     * 获取当前正在执行的进度百分比.<br>
     * 该方法需要在实现类中自行处理<br>
     * @since v1.0.0
     * 参数名 参数类型 参数描述
     * @return 返回类型 返回类型描述
     * <br>
     * --------------------------------------<br>
     * 编辑历史<br>
     * 2014年10月13日::X03::创建此方法<br>
     *********************************************/
    public abstract int getProgress();

    /********************************************
     * 获取执行结果.<br>
     * 方法业务逻辑详细描述……<br>
     * 参数名 参数类型 参数描述
     * @return 返回类型 返回类型描述
     * <br>
     *********************************************/
    public abstract Object getResult();

    /********************************************
     * resolve<br>
     * 定时自我销毁<br>
     * void
     * <br>
     *********************************************/
    private void resolve() {
        final Timer timer = new Timer();
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                taskExecutor.pull(taskId);// 调用外面的线程池 销毁自己
                timer.cancel();
            }
        };
        // 如果自动销毁时间被定义过，则使用该线程的自有时间，否则使用线程池的通用时间
        timer.schedule(timerTask, getDestroyTime() == 0 ? taskExecutor.getDestroyTime() : getDestroyTime());
    }

    @Override
    public void run() {
        this.execute();// 执行业务
        this.getTaskExecutor().complate(taskId, this);// 完成后自动将自己移到完成队列中
        this.resolve();// 进入自我销毁倒计时
    }

    public String getTaskId() {
        return taskId;
    }

    public void setTaskId(String taskId) {
        this.taskId = taskId;
    }

    public AsyncTaskExecutor getTaskExecutor() {
        return taskExecutor;
    }

    public void setTaskExecutor(AsyncTaskExecutor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }

    public int getDestroyTime() {
        return destroyTime;
    }

    public void setDestroyTime(int destroyTime) {
        this.destroyTime = destroyTime;
    }

}
